#include "ErrorPrinter.h"

namespace LALG
{

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErrorPrinter
 *      Method:  ErrorPrinter
 * Description:  Constrói um novo contêiner de erros
 *--------------------------------------------------------------------------------------
 */
ErrorPrinter::ErrorPrinter()
{
    name =
    {
        { ERR_LEX, "lexical error" },
        { ERR_SIN, "syntax error" },
        { ERR_SEM, "semantic error" },

        { LEX_UNKNOWN,      "token '%s' not allowed" },
        { LEX_MF_INTEGER,   "integer number '%s' malformed" },
        { LEX_MF_REAL,      "real number '%s' malformed" },
        { LEX_MF_ID,        "identifier '%s' malformed" },
        { LEX_BCNC,         "unclosed block comment" },
        { LEX_LONG_ID,      "very large identifier '%s'" },

        { SIN_SEMICOLON_EXPECTED,   "expected ';', got '%s'" },
        { SIN_ID_EXPECTED,          "expected identifier, got '%s'" },
        { SIN_BEGIN_EXPECTED,       "expected 'begin', got '%s'" },
        { SIN_END_EXPECTED,         "expected 'readln', 'writeln', 'repeat', 'if', 'begin', 'while', identifier or 'end', got '%s'" },
        { SIN_EQUAL_EXPECTED,       "expected '=', got '%s'" },
        { SIN_COLON_EXPECTED,       "expected ':', got '%s'" },
        { SIN_TYPE_EXPECTED,        "expected 'integer' or 'real', got '%s'" },
        { SIN_LPAREN_EXPECTED,      "expected '(', got '%s'" },
        { SIN_RPAREN_EXPECTED,      "expected ')', got '%s'" },
        { SIN_NUMBER_EXPECTED,      "expected number, got '%s'" },
        { SIN_RELATION_EXPECTED,    "expected relation '=', '<>', '>=', '<=', '>' or '<', got '%s'" },
        { SIN_OPERATOR_EXPECTED,    "expected operator '-', '+', '*' or '/', got '%s'" },
        { SIN_FACTOR_EXPECTED,      "expected number, identifier or '(', got '%s'" },
        { SIN_RETURN_EXPECTED,      "expected 'return', got '%s'" },
        { SIN_DOT_EXPECTED,         "expected '.', got '%s'" },
        { SIN_PROGRAM_EXPECTED,     "expected 'program', got '%s'" },
        { SIN_UNTIL_EXPECTED,       "expected 'until', got '%s'" },
        { SIN_THEN_EXPECTED,        "expected 'then', got '%s'" },
        { SIN_ASSIGN_EXPECTED,      "expected ':=' or '(', got '%s'" },
        { SIN_DO_EXPECTED,          "expected 'do', got '%s'" },

        { SIN_INVALID_CMD,      "invalid command" },

        { SIN_SEMICOLON,    ";" },
        { SIN_COLON,        ":" },
        { SIN_DOT,          "." },
        { SIN_BEGIN,        "begin" },
        { SIN_END,          "end" },
        { SIN_EQUAL,        "=" },
        { SIN_RETURN,       "return" },
        { SIN_RPAREN,       ")" },

        { SIN_SYN_TOKEN,    "will skip tokens until '%s'" },
        { SIN_SKIPPED,      "token found will be skipped" },

        { SEM_ALREADY_DECLARED,  "redefinition of '%s', previously defined as program, constant, variable or procedure" },
        { SEM_VAR_NOT_DECLARED,  "identifier '%s' is not a declared variable or a parameter on this scope" },
        { SEM_PROC_NOT_DECLARED, "identifier '%s' is not a declared procedure on this scope" },
        { SEM_CONST_ATTRIB,      "identifier '%s' is a constant value, it can not receive an value" },
        { SEM_PARAMETERS_ERROR,  "invalid parameters for procedure '%s'" },
        { SEM_ATTRIBUTION,       "can not assign an float value to the variable '%s', whose type is integer" },
        { SEM_DIVISION,          "division can only be made between two integers" },
        { SEM_READLN_WRITELN,    "command '%s' should have only arguments with same type" }
    };

    happened = false;
}

/*
 *--------------------------------------------------------------------------------------
 *       Class:  ErrorPrinter
 *      Method:  print
 * Description:  Imprime um erro/aviso
 *--------------------------------------------------------------------------------------
 */
void ErrorPrinter::print(int lineno, ErrorType type, ErrorWhat what, string text, int synToken)
{
    printf("Line %d: %s, ", lineno, name[type].c_str());
    printf(name[what].c_str(), text.c_str());

    if(type == ERR_SIN)
    {
        if(synToken == 0)
            printf(", %s\n", name[SIN_SKIPPED].c_str());
        else
        {
            printf(", ");
            printf(name[SIN_SYN_TOKEN].c_str(), name[synToken].c_str());
            printf("\n");
        }
    }
    else
    {
        printf("\n");
    }

    happened = true;
}

}
